/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package rules;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import types.ColoringInfo;
import types.ISudokuMatrix;
import utils.RuleHelper;
import types.ISudokuMatrix;
import types.ISudokuMatrix;

/**
 *
 * @author ali
 */
public class QuadratSeveralFree implements Rule{

    int quadrat = 0;
    int numberOfMissedDigits = -1;

    Collection checkedBlocks = new HashSet();
    Collection checkedCols = new HashSet();
    Collection checkedRows =new HashSet();

    public String getName() {
        return QuadratSeveralFree.class.getSimpleName();
    }

    public String getDesc() {
        return "Betrachte die anderen (beliebig vielen) leeren Felder im Quadrat und versuche \ndie Kandidaten solange auszuschlißen, bis" +
                "nur eine kandidat übrig bleibt.";
    }

    public boolean isApplicable(int x, int y, ISudokuMatrix matrix) {
        System.out.println("Trying to apply rule "+ this.getName()+ " for "+x+","+y);
        try {
            this.setQuadrat(x, y);

            int[] digits = RuleHelper.collectionToIntArray(RuleHelper.getDigitsSameQuadrat(x, y, matrix));

            Collection missedDigits = RuleHelper.getMissingdigitsInQuadratOrColOrRow(RuleHelper.intArrayToCollection(digits));

            this.checkedBlocks.add(RuleHelper.calculateQuadratNumber(x, y));


            this.numberOfMissedDigits = missedDigits.size();

            int quadratNumber = RuleHelper.calculateQuadratNumber(x, y);

            System.out.print("missed digits in Quadrat " + quadratNumber + ": ");
            RuleHelper.printCollection(missedDigits);

            Collection candidates = RuleHelper.cloneCollection(missedDigits);

            Iterator iter = missedDigits.iterator();
            while (iter.hasNext()) {
                Integer digit = (Integer) iter.next();

                if (RuleHelper.existsDigitInCol(digit, y, matrix) || RuleHelper.existsDigitInRow(digit, x, matrix)) {
                    candidates.remove(digit);
                    System.out.println("\n" + digit + " exists in Col " + y + " and/or in Row: " + x);
                    System.out.println(digit + " can be exculuded.");
                }
                if (RuleHelper.existsDigitInCol(digit, y, matrix))
                {
                    this.checkedCols.add(y);
                }

                if (RuleHelper.existsDigitInRow(digit, x, matrix))
                {
                    this.checkedRows.add(x);
                }
            }

            // numberOfMissedDigits-1 zahlen konnten asugeschloßen werden--> true
            if (candidates.size() == 1) {
                System.out.println("Rule applicable");
                return true;
            }


            missedDigits = RuleHelper.cloneCollection(candidates);

            System.out.print("Candidates:");
            RuleHelper.printCollection(candidates);

            Iterator iter1 = candidates.iterator();
            while (iter1.hasNext()) {
                int counter = 0;
                Integer a = (Integer) iter1.next();
                System.out.println("\nVersuch " + a + " bei anderen Felder auszuschließen. ");
               
                for (int i = 0; i < digits.length; i++) {
                    //ignoriere leere Zeilen + den leeren feld selbst
                    if (digits[i] != 0 || i == y) {
                        continue;
                    }
                    int col = RuleHelper.calculateColUsingQuadrat(quadratNumber, i);
                    int row = RuleHelper.calculateRowUsingQuadrat(quadratNumber, i);
                    if (RuleHelper.existsDigitInCol(a,col, matrix) ||
                            RuleHelper.existsDigitInRow(a, row, matrix)) {
                        System.out.println("\n" + a + " exists in Col " + col  + " and/or in Row " + row );

                        counter++;

                    }
                    if (RuleHelper.existsDigitInCol(a, col, matrix))
                    {
                        this.checkedCols.add(col);
                    }

                    if (RuleHelper.existsDigitInRow(a, row, matrix))
                    {
                        this.checkedRows.add(row);
                    }

                }
                if (counter == numberOfMissedDigits - 1) {
                    {
                  //      missedDigits.remove(a);

                        System.out.println(a + " konnte bei allen anderen Felder ausgeschloßen werden.");
                        System.out.println("Rule applicable");
                        return true;
                  //      System.out.println(a + " can be exculuded.");

                    }
                }
            }
            if (missedDigits.size() <= 1) {
                System.out.println("Rule applicable");
                return true;
            }

        } catch (Exception ex) {
            Logger.getLogger(ColumnTwoFree.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;

    }

    public int getWeight(int QuadratNumber) {


        //für jedes feld einmal Zeile und einmal Spalte
        
        //Quadrate in den Ecken
        if (QuadratNumber == 1 || QuadratNumber == 3 || QuadratNumber == 7 || QuadratNumber == 9) {
            return (numberOfMissedDigits *(6*2));
        } else
        {
            return (numberOfMissedDigits *(5*2));
        }
    }

    public int compareTo(Rule o) {
        if (this.getWeight(this.getQuadrat())<o.getWeight(o.getQuadrat()))
            return -1;
        else if (this.getWeight(this.getQuadrat())>o.getWeight(o.getQuadrat()))
            return 1;
        else
            return 0;
    }

    public void setQuadrat(int x, int y) throws Exception {

            this.quadrat = RuleHelper.calculateQuadratNumber(x, y);

    }

    public int getQuadrat() {
       return this.quadrat;
    }

    public ColoringInfo getCheckedUnits(int x, int y, ISudokuMatrix matrix) {
         ColoringInfo ci = new ColoringInfo();

        ci.setBlocks(this.checkedBlocks);
        ci.setColums(this.checkedCols);
        ci.setRows(this.checkedRows);

        return ci;
    }
}


